package main

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"net"
	"time"
)

const (
	TCP_STATE_CONNECTED = iota
	TCP_STATE_DISCONNECTED
	TCP_STATE_DATA
	TCP_STATE_ERROR
)

type TcpServerCall func(conn net.Conn, state int, err error, data []byte, datasize uint32)

type TcpServer struct {
	Port          uint64
	OnServerState TcpServerCall
}

func NewTcpServer() *TcpServer {
	return &TcpServer{}
}
func (s *TcpServer) Start(port uint64) error {
	s.Port = port

	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", s.Port))
	if err != nil {
		return err
	}

	go func() {
		for {
			conn, err := listener.Accept()
			if err != nil {
				if s.OnServerState != nil {
					s.OnServerState(conn, TCP_STATE_ERROR, err, nil, 0)
				}
				continue
			}
			go s.handleConnection(conn)
		}
	}()
	return nil
}

func (s *TcpServer) handleConnection(conn net.Conn) {
	defer conn.Close()
	if s.OnServerState != nil {
		s.OnServerState(conn, TCP_STATE_CONNECTED, nil, nil, 0)
	}

	if tcpConn, ok := conn.(*net.TCPConn); ok {
		tcpConn.SetNoDelay(true)
		tcpConn.SetReadBuffer(1024 * 32)
		tcpConn.SetWriteBuffer(1024 * 32)            //视频流媒体服务 256K,IM 32K(保持10万并发)
		tcpConn.SetKeepAlive(true)                   // 保持长连接活跃
		tcpConn.SetKeepAlivePeriod(10 * time.Minute) // 减少保活探测频率
	}

	for {
		data, err := ReadBytes(conn)

		if err != nil {
			if err == io.EOF {
				if s.OnServerState != nil {
					s.OnServerState(conn, TCP_STATE_DISCONNECTED, err, data, 0)
				}
			} else {
				if s.OnServerState != nil {
					s.OnServerState(conn, TCP_STATE_ERROR, err, data, 0)
				}
			}
			break
		}
		ss := len(data)

		if s.OnServerState != nil {
			s.OnServerState(conn, TCP_STATE_DATA, nil, data, uint32(ss))
		}
	}
}

// read 4byte data
func ReadUint32(conn net.Conn) (uint32, error) {
	data, err := readBytes(conn, 4)
	if err != nil {
		return 0, err
	}
	return binary.BigEndian.Uint32(data), nil
}

// read n bytes from conn
func readBytes(conn net.Conn, length uint32) ([]byte, error) {
	var data bytes.Buffer
	slen := length
	count := 0
	for {
		buf := make([]byte, slen)
		n, err := conn.Read(buf)
		if err != nil {
			return data.Bytes(), err
		}
		count += n
		data.Write(buf[:n])
		if uint32(count) >= length {
			break
		}
		slen -= uint32(n)
	}
	return data.Bytes(), nil
}

// 4byte length + data
func ReadBytes(conn net.Conn) ([]byte, error) {
	length, err := ReadUint32(conn)
	if err != nil {
		return nil, err
	}
	data, err := readBytes(conn, length)
	if err != nil {
		return nil, err
	}
	return data, nil
}
func TcpSendBytes(conn net.Conn, data []byte) error {
	if conn == nil {
		return nil
	}
	buf := data
	for len(buf) > 0 {
		n := 0
		var err error
		//如果是大包，则分包发送
		if len(buf) > 1460 {
			n, err = conn.Write(buf[0:1460])
		} else {
			n, err = conn.Write(buf)
		}

		if err != nil {
			return err
		}
		buf = buf[n:]
	}
	return nil
}
